﻿/*
 * Created by SharpDevelop.
 * User: wwlng1
 * Date: 9/12/2014
 * Time: 06:31 PM
 * 
 * 
 *  2015-02-17 Add ResetInstance for reseting Outlook instance after any failure 
 */
using System;
using System.Net;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.ComponentModel;

using cogs.Services;

namespace cogs
{
	/// <summary>
	/// Description of SyncManager.
	/// </summary>
	public class SyncManager: INotifyPropertyChanged
	{
		
		private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
		
		private string statusMessage = "";
		public string StatusMessage {
			get { return statusMessage; }
			set {
				statusMessage = value;
				OnPropertyChanged("StatusMessage");
			}
		}
		
		// Declare the event
		public event PropertyChangedEventHandler PropertyChanged;

		
		public SyncManager()
		{
			Initialize();
		}
		
		
		private void Initialize()
		{

		}

		/// <summary>
		/// Synchorize from Outlook calendar to Google calendar (One direction)
		/// 
		/// </summary>
		public async Task SynchronizeAsync()
		{

			/*
			 * 1 way sync logic:
			 * 
			 * For a in Outlook
			 *   For e in Google
			 *
			 * if a not in Google, then create e?
			 * 
			 * 
			 * For e in Google
			 *   For a in Outlook
			 * 
			 * if e not in Outlook, then remove e?
			 * 
			 */
			
			log.Info("===========================================================================");
			UpdateStatus("Start Synchronize...");
			
			try {
				int DaysInThePast = Settings.Default.DaysInThePast;
				int DaysInTheFuture = Settings.Default.DaysInTheFuture;
				
				OutlookCalendarService outlook = OutlookCalendarService.Instance;
				GoogleCalendarService google = new GoogleCalendarService();
				
				google.CurrentCalendarId = Settings.Default.GoogleCalendarId;
				
				UpdateStatus("Read data from Outlook Calendar...");
				List<Appointment> OutlookEntries = outlook.getCalendarEntriesInRange(DaysInThePast, DaysInTheFuture);
				foreach (Appointment a in OutlookEntries) {
					log.DebugFormat("=> {0}", a);
				}
				

				log.Debug("Getting Current Calendar...");				
				string currentCalendar = google.CurrentCalendar.Name;
				
				UpdateStatus("Read data from Google Calendar["+currentCalendar+"]...");				
				List<Appointment> GoogleEntries = google.GetCalendarEntriesInRange(DaysInThePast, DaysInTheFuture, true);
				foreach (Appointment a in GoogleEntries) {
					log.DebugFormat("=> {0}", a);
				}
				
				var newGoogleList = new List<Appointment>();
				var delGoogleList = new List<Appointment>();
				var newOutlookList = new List<Appointment>();
				
				UpdateStatus("Identifing what need to be synchorized...");
	
				foreach (Appointment o in OutlookEntries) {
					bool found = false;
					foreach (Appointment g in GoogleEntries) {
						if (o.Equals(g)) {
							found = true;
							break;
						}
					}	
					if (!found) {
						newGoogleList.Add(o);
					}
				}
	
				
				foreach (Appointment g in GoogleEntries) {
					bool found = false;
					foreach (Appointment o in OutlookEntries) {
						if (g.Equals(o)) {
							found = true;
							break;
						}
					}
					if (!found) {
						delGoogleList.Add(g);
					}
				}
				
	
				if (delGoogleList.Count > 0) {
					UpdateStatus("Deleting " + delGoogleList.Count + " Google Calendar Entries...");
					foreach (Appointment d in delGoogleList) {
						await google.DeleteCalendarEntryAsync(d);
						log.DebugFormat("Delete Async: {0}", d);
					}
				}
				
				if (newGoogleList.Count > 0) {
					UpdateStatus("Creating " + newGoogleList.Count + " Google Calendar Entries...");       		
					foreach (Appointment n in newGoogleList) {
						var a = await google.InsertCalendarEntryAsync(n);
						
						//TODO: Update Outlook side to have google Etag or googleID??
						
						log.DebugFormat("Create Async: {0}", n);
					}
				}
	       		
				 
				UpdateStatus("Synchronization completed at " + DateTime.Now);
			} catch (Exception e) {
				log.Error("Error during synchronization:"+e.Message);
				log.Debug("Detail:", e);
				UpdateStatus("Synchronization failure at " + DateTime.Now);
				OutlookCalendarService.ResetInstance();
				log.Info("Reset Instance...");
			}
		}
		
		private void UpdateStatus(string message)
		{
			log.Info(message);
			StatusMessage = message;
		}
		
		protected void OnPropertyChanged(string name)
		{
			PropertyChangedEventHandler handler = PropertyChanged;
			if (handler != null) {
				handler(this, new PropertyChangedEventArgs(name));
			}			
		}
		
	}
}
